import _cloneDeep from 'lodash/cloneDeep';

const getBaseUrl = (context) => {
    var location = window.document.location;
    var pagePath = location.pathname;
    context = context || "";
    if (context != "") {
        var pos = pagePath.indexOf("/" + context);
        context = pos > -1 ? context : "";
        return location.protocol + "//" + location.host + "/" + context;
    }
    else {
        return location.protocol + "//" + location.host;
    }
};
function getHtmlContent(Url) {
    return new Promise((resolve, reject) => {
        fetch(Url).then(res => {
            resolve(res.text());
        }).catch(err => {
            reject(err);
        });
    });
}

const changeStringToDom = async (baseUrl, html, name) => {
    const contain = document.createElement('div');
    contain.id = '_esbuild_micro_' + name;
    contain.innerHTML = html;
    const jsData = await getChangeJsModule(baseUrl, contain);
    const cssData = await getChangeCssModule(baseUrl, contain);
    return { contain, jsData, cssData };
};
const getChangeJsModule = async (baseUrl, contain) => {
    const moduleTags = contain.querySelectorAll('script[type=module]');
    const modulePreload = contain.querySelectorAll('link[rel=modulepreload]');
    const app = [];
    for (let i = 0; i < modulePreload.length; i++) {
        const moduleTag = modulePreload[i];
        const name = moduleTag.href.substring(moduleTag.href.lastIndexOf('/') + 1);
        const href = moduleTag.href.replace(getBaseUrl(""), baseUrl);
        app.push({ name: name, url: href, content: "" });
        contain.removeChild(moduleTag);
    }
    for (let i = 0; i < moduleTags.length; i++) {
        const moduleTag = moduleTags[i];
        const name = moduleTag.src.substring(moduleTag.src.lastIndexOf('/') + 1);
        const src = moduleTag.src.replace(getBaseUrl(""), baseUrl);
        app.push({ name: name, url: src, content: "" });
        contain.removeChild(moduleTag);
    }
    console.log('app', { app });
    return app;
};
const getChangeCssModule = async (baseUrl, contain) => {
    const moduleTags = contain.querySelectorAll('link[rel=stylesheet]');
    if (!moduleTags || !moduleTags.length) {
        return;
    }
    const app = [];
    for (let i = 0; i < moduleTags.length; i++) {
        const moduleTag = moduleTags[i];
        const name = moduleTag.href.substring(moduleTag.href.lastIndexOf('/') + 1);
        const href = moduleTag.href.replace(getBaseUrl(""), baseUrl);
        app.push({ name: name, url: href });
        await loadReplaceCss(contain, moduleTag, href, name);
    }
    return app;
};
const loadReplaceCss = async (contain, moduleTag, url, keyId) => {
    const css = await getHtmlContent(url);
    const style = document.createElement('style');
    style.id = keyId;
    style.innerHTML = css;
    moduleTag.removeAttribute('href');
    contain.insertBefore(style, moduleTag);
    contain.removeChild(moduleTag);
};

var SysMsgType;
(function (SysMsgType) {
    SysMsgType["js"] = "js";
    SysMsgType["network"] = "network";
    SysMsgType["res"] = "res";
    SysMsgType["performance"] = "performance";
})(SysMsgType || (SysMsgType = {}));
var LOGLEVEL;
(function (LOGLEVEL) {
    LOGLEVEL["debug"] = "debug";
    LOGLEVEL["error"] = "error";
    LOGLEVEL["info"] = "info";
    LOGLEVEL["warn"] = "warn";
    LOGLEVEL["assert"] = "assert";
    LOGLEVEL["clear"] = "clear";
})(LOGLEVEL || (LOGLEVEL = {}));
var STYLETYPE;
(function (STYLETYPE) {
    STYLETYPE["css"] = "%c";
    STYLETYPE["number"] = "%d";
    STYLETYPE["dom"] = "%o";
    STYLETYPE["object"] = "%O";
})(STYLETYPE || (STYLETYPE = {}));
var MESSAGESTYLE;
(function (MESSAGESTYLE) {
    MESSAGESTYLE["debug"] = "color: #FFCCFF;font-size: 12px;text-decoration: underline;";
    MESSAGESTYLE["error"] = "color: #990033;font-size: 12px;font-weight: bold;text-decoration: underline;";
    MESSAGESTYLE["info"] = "color: #33FF33;font-size: 12px;text-decoration: underline;";
    MESSAGESTYLE["warn"] = "color: #FFCC00;font-size: 12px;font-weight: bold;text-decoration: underline;";
    MESSAGESTYLE["assert"] = "color: #99FFFF;font-size: 12px;font-weight: bold;text-decoration: underline;";
    MESSAGESTYLE["clear"] = "color: #3366FF;font-size: 12px;font-weight: bold;";
    MESSAGESTYLE["moudle"] = "color: #FF66FF;font-size: 12px;font-weight: bold;";
})(MESSAGESTYLE || (MESSAGESTYLE = {}));
class ConsoleLogger {
    logData = {
        moudle: '',
        level: LOGLEVEL.info,
        styleType: STYLETYPE.css
    };
    console;
    constructor(moudle, con) {
        this.logData.moudle = moudle;
        this.console = con || window.console;
    }
    warn(message, ...argc) {
        const level = LOGLEVEL.error;
        const style = STYLETYPE.css;
        if (window.__POWERED_BY_MICO__.debugger) {
            const logArgs = [`${STYLETYPE.css}[${this.logData.moudle}]-[${message}]-{${style}}`, MESSAGESTYLE[level], ...argc];
            this.console[LOGLEVEL[level]](...logArgs);
        }
    }
    log(message, loglevel, ...argc) {
        let level;
        if (typeof loglevel === 'object') {
            level = LOGLEVEL.info;
            argc.push(loglevel);
        }
        else if (loglevel && MESSAGESTYLE[loglevel]) {
            level = loglevel || this.logData.level;
        }
        else {
            level = LOGLEVEL.info;
            argc.push(loglevel);
        }
        const style = this.logData.styleType;
        if (window.__POWERED_BY_MICO__.debugger) {
            let logArgs = [`${STYLETYPE.css}[${this.logData.moudle}]-${style}[${message}]`, MESSAGESTYLE.moudle, MESSAGESTYLE[level], ...argc];
            switch (style) {
                case STYLETYPE.dom:
                    logArgs = [`${STYLETYPE.css}[${this.logData.moudle}]-[${message}]-{${style}}`, MESSAGESTYLE[level], ...argc];
                    break;
                case STYLETYPE.object:
                    logArgs = [`${STYLETYPE.css}[${this.logData.moudle}]-[${message}]-{${style}}`, MESSAGESTYLE[level], ...argc];
                    break;
            }
            switch (level) {
                case LOGLEVEL.assert:
                    this.console[LOGLEVEL.assert](...argc, `${this.logData.moudle}:${style + message}`, MESSAGESTYLE.assert);
                    break;
                default:
                    this.console[LOGLEVEL[level]](...logArgs);
                    break;
            }
        }
    }
}
new ConsoleLogger('global', console);

const console$3 = new ConsoleLogger('微应用-主应用-App类');
const activeApp = async (app) => {
    const dic = window.__POWERED_BY_MICO__;
    console$3.log('开始激活微应用');
    if (dic.partitionAppDic[app.name]) {
        dic.activeAppDic[app.name] = _cloneDeep(dic.partitionAppDic[app.name]);
        document.getElementById(app.domId.replace('#', '')).appendChild(app.htmlElement);
        if (dic.partitionAppDic[app.name].clientLife) {
            dic.partitionAppDic[app.name].clientLife.mount({ container: app.htmlElement });
        }
        delete dic.partitionAppDic[app.name];
        return false;
    }
    else {
        if (!document.getElementById(app.domId.replace('#', '')).querySelector('#' + app.htmlElement.id)) {
            document.getElementById(app.domId.replace('#', '')).appendChild(app.htmlElement);
            await app.execApp();
            app.htmlElement = document.getElementById(app.htmlElement.id);
            dic.activeAppDic[app.name].htmlElement = document.getElementById(app.htmlElement.id);
        }
        else {
            console$3.log('执行激活微应用，单当前应用未unmont');
            return false;
        }
        return true;
    }
};
const partitionApp = async (app) => {
    const dic = window.__POWERED_BY_MICO__;
    if (dic.activeAppDic[app.name] && !dic.partitionAppDic[app.name]) {
        try {
            dic.partitionAppDic[app.name] = _cloneDeep(dic.activeAppDic[app.name]);
            delete dic.activeAppDic[app.name];
            const parent = document.getElementById(app.htmlElement.id).parentElement;
            parent.removeChild(app.htmlElement);
            console$3.log('沙箱微应用成功', { partitionApp: dic.partitionAppDic[app.name] });
        }
        catch (e) {
            return;
        }
    }
};
class App {
    baseUrl;
    name;
    domId;
    appJs;
    appCss;
    htmlContent;
    htmlElement;
    constructor(param) {
        Object.keys(param).forEach((key) => {
            this[key] = param[key];
        });
    }
    bootstrap = () => {
        const dic = window.__POWERED_BY_MICO__;
        if (dic.activeAppDic[this.name].clientLife && dic.activeAppDic[this.name].clientLife.bootstrap) {
            dic.activeAppDic[this.name].clientLife.bootstrap({ container: this.htmlElement });
            console$3.log('微应用-子应用bootstrap成功', { name: this.name });
        }
        console$3.log('bootstrap成功', { name: this.name });
    };
    mount = () => {
        const dic = window.__POWERED_BY_MICO__;
        activeApp(this).then(res => {
            if (res) {
                if (dic.activeAppDic[this.name].clientLife && dic.activeAppDic[this.name].clientLife.mount) {
                    const props = { container: this.htmlElement };
                    if (dic.globalState) {
                        props.globalState != dic.globalState;
                    }
                    dic.activeAppDic[this.name].clientLife.mount(props);
                    console$3.log('微应用-子应用mount成功', { name: this.name });
                }
            }
            console$3.log('mount成功', { name: this.name });
        });
        console$3.log('激活微应用成功');
    };
    unmount = () => {
        const dic = window.__POWERED_BY_MICO__;
        if (dic.activeAppDic[this.name].clientLife && dic.activeAppDic[this.name].clientLife.unmount) {
            dic.activeAppDic[this.name].clientLife.unmount({ container: this.htmlElement });
            console$3.log('微应用-子应用unmount成功', { name: this.name });
        }
        partitionApp(this);
        console$3.log('unmount成功', { name: this.name });
    };
    distory = () => {
        const dic = window.__POWERED_BY_MICO__;
        this.htmlContent = '';
        const name = this.name;
        this.htmlElement.parentElement.removeChild(this.htmlElement);
        if (dic.activeAppDic[this.name] && dic.activeAppDic[this.name].clientLife && dic.activeAppDic[this.name].clientLife.unmount) {
            dic.activeAppDic[this.name].clientLife.unmount({ container: this.htmlElement });
        }
        if (dic.partitionAppDic[this.name] && dic.partitionAppDic[this.name].clientLife && dic.partitionAppDic[this.name].clientLife.unmount) {
            dic.partitionAppDic[this.name].clientLife.unmount({ container: this.htmlElement });
        }
        this.htmlElement.innerHTML = "";
        delete window.__POWERED_BY_MICO__.activeAppDic[this.name];
        delete window.__POWERED_BY_MICO__.partitionAppDic[this.name];
        for (let ss in this) {
            delete this[ss];
        }
        console$3.log('distory成功', { name });
    };
    clientLife;
    execApp = async () => {
        try {
            const proxy = window.__POWERED_BY_MICO__.clientAppDicProxy;
            if (!proxy[this.name]) {
                proxy[this.name] = {};
            }
            for (let i = 0; i < this.appJs.length; i++) {
                if (proxy[this.name][this.appJs[i].name] && proxy[this.name][this.appJs[i].name].default) {
                    proxy[this.name][this.appJs[i].name].default.default.mount({ container: this.htmlElement });
                    return;
                }
                proxy[this.name][this.appJs[i].name] = await (async function (window, url) { const res = await import(url); return res; })(proxy, this.appJs[i].url);
            }
            console$3.log('execApp-执行动态import结束', { name: this.name });
        }
        catch (e) {
            console$3.warn('加载出错', SysMsgType.js, { error: e });
            throw new Error('执行子应用失败');
        }
    };
}

const console$2 = new ConsoleLogger('微应用-主应用');
const start = (debug = true) => {
    window.__POWERED_BY_MICO__ = { activeAppDic: {}, partitionAppDic: {}, clientAppDicProxy: {}, debugger: debug, globalState: {} };
    console$2.log('开启微应用-主应用初始化');
};
const loadMicro = async (param) => {
    const dic = window.__POWERED_BY_MICO__;
    try {
        if (dic.partitionAppDic[param.name]) {
            await activeApp(dic.partitionAppDic[param.name]);
            return dic.activeAppDic[param.name];
        }
        if (dic.activeAppDic[param.name]) {
            const app_tmp = dic.activeAppDic[param.name];
            document.getElementById(app_tmp.domId.replace('#', '')).innerHTML = "";
            document.getElementById(app_tmp.domId.replace('#', '')).appendChild(app_tmp.htmlElement);
            return app_tmp;
        }
        const html = await getHtmlContent(param.baseUrl);
        const htmlinfo = await changeStringToDom(param.baseUrl, html, param.name);
        const app = new App({
            name: param.name, appJs: htmlinfo.jsData, appCss: htmlinfo.cssData, domId: param.domId,
            htmlContent: html, baseUrl: param.baseUrl, htmlElement: htmlinfo.contain
        });
        dic.activeAppDic[param.name] = app;
        console$2.log('加载微引用成功,后续将执行子应用microClientBind', { app: { ...dic.activeAppDic[param.name] } });
        app.bootstrap();
        app.mount();
        return app;
    }
    catch (e) {
        console$2.warn('加载子应用失败', { e });
        if (dic.activeAppDic[param.name]) {
            delete dic.activeAppDic[param.name];
        }
        throw new Error("加载子应用失败");
    }
};

const console$1 = new ConsoleLogger('微应用-子应用');
const microClientBind = (name, props) => {
    if (window.__POWERED_BY_MICO__) {
        try {
            const dic = window.__POWERED_BY_MICO__;
            dic.activeAppDic[name].clientLife = { bootstrap: props.bootstrap, mount: props.mount, unmount: props.unmount };
            microClientBind.default = { bootstrap: props.bootstrap, mount: props.mount, unmount: props.unmount };
            console$1.log('执行子应用microClientBind绑定-子应用绑定', { bootstrap: props.bootstrap, mount: props.mount, unmount: props.unmount });
        }
        catch (e) {
            console$1.log('执行绑定微应用失败', { error: e });
        }
    }
    else {
        throw new Error("主应用微应用初始化失败");
    }
};

export { loadMicro, microClientBind, start };
